﻿/*!	@file
	共通設定ダイアログボックス、「メインメニュー」ページ

	@author Uchi
*/
/*
	Copyright (C) 2010, Uchi
	Copyright (C) 2018-2022, Sakura Editor Organization

	SPDX-License-Identifier: Zlib
*/

#include "StdAfx.h"
#include "prop/CPropCommon.h"
#include "env/CShareData.h"
#include "env/CShareData_IO.h"
#include "typeprop/CImpExpManager.h"
#include "dlg/CDlgInput1.h"
#include "util/shell.h"
#include "apiwrap/StdControl.h"
#include "sakura_rc.h"
#include "sakura.hh"
#include "config/app_constants.h"
#include "String_define.h"

// TreeView 表示固定初期値

static const DWORD p_helpids[] = {
	IDC_COMBO_FUNCKIND,				HIDC_COMBO_FUNCKIND,				//機能の種別
	IDC_LIST_FUNC,					HIDC_LIST_FUNC,						//機能一覧
	IDC_TREE_RES,					HIDC_TREE_RES,						//メニュー一覧
	IDC_BUTTON_DELETE,				HIDC_BUTTON_TREE_DELETE,			//メニューから機能削除
	IDC_BUTTON_INSERT_NODE,			HIDC_BUTTON_TREE_INSERT_NODE,		//メニューへノード追加
	IDC_BUTTON_INSERTSEPARATOR,		HIDC_BUTTON_TREE_INSERT_SEPARATOR,	//メニューへ区切線挿入
	IDC_BUTTON_INSERT,				HIDC_BUTTON_TREE_INSERT,			//メニューへ機能挿入(上)
	IDC_BUTTON_INSERT_A,			HIDC_BUTTON_TREE_INSERT_A,			//メニューへ機能挿入(下)
	IDC_BUTTON_ADD,					HIDC_BUTTON_TREE_ADD,				//メニューへ機能追加
	IDC_BUTTON_UP,					HIDC_BUTTON_TREE_UP,				//メニューの機能を上へ移動
	IDC_BUTTON_DOWN,				HIDC_BUTTON_TREE_DOWN,				//メニューの機能を下へ移動
	IDC_BUTTON_RIGHT,				HIDC_BUTTON_TREE_RIGHT,				//メニューの機能を右へ移動
	IDC_BUTTON_LEFT,				HIDC_BUTTON_TREE_LEFT,				//メニューの機能を左へ移動
	IDC_BUTTON_IMPORT,				HIDC_BUTTON_IMPORT,					//メニューのインポート
	IDC_BUTTON_EXPORT,				HIDC_BUTTON_EXPORT,					//メニューのエクスポート
	IDC_BUTTON_CHECK,				HIDC_BUTTON_NENU_CHECK,				//メニューの検査
	IDC_BUTTON_CLEAR,				HIDC_BUTTON_TREE_CLEAR,				//メニューをクリア
	IDC_BUTTON_INITIALIZE,			HIDC_BUTTON_TREE_INITIALIZE,		//メニューを初期状態に戻す
	IDC_CHECK_KEY_PARENTHESES,		HIDC_CHECK_KEY_PARENTHESES,			//アクセスキーを必ず( )付で表示(&P)
	0, 0
};

// 内部使用変数
// 機能格納(Work)
struct SMainMenuWork {
	std::wstring	m_sName;		// 名前
	EFunctionCode	m_nFunc;		// Function
	WCHAR			m_sKey[2];		// アクセスキー
	bool			m_bDupErr;		// アクセスキー重複エラー
	bool			m_bIsNode;		// ノードか否か（ノードでもm_nFuncがF_NODE(0)でないものがあるため）
};

static	std::map<int, SMainMenuWork>	msMenu;	// 一時データ
static	int		nMenuCnt = 0;					// 一時データ番号

// ローカル関数定義
static HTREEITEM TreeCopy( HWND, HTREEITEM, HTREEITEM, bool, bool );
static const WCHAR * MakeDispLabel( SMainMenuWork* );

static	int 	nSpecialFuncsNum;		// 特別機能のコンボボックス内での番号

//  TreeViewキー入力時のメッセージ処理用
static HWND		m_hwndDlg;

// TreeViewラベル編集時のメッセージ処理用
static WNDPROC	m_wpEdit = nullptr;

/*!
	@param hwndDlg ダイアログボックスのWindow Handle
	@param uMsg メッセージ
	@param wParam パラメータ1
	@param lParam パラメータ2
*/
INT_PTR CALLBACK CPropMainMenu::DlgProc_page(
	HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
	return DlgProc( reinterpret_cast<pDispatchPage>(&CPropMainMenu::DispatchEvent), hwndDlg, uMsg, wParam, lParam );
}

// TreeViewキー入力時のメッセージ処理
LRESULT CALLBACK CPropMainMenu::TreeViewProc(
	HWND	hwndTree,		// handle to dialog box
	UINT	uMsg,			// message
	WPARAM	wParam,			// first message parameter
	LPARAM	lParam,			// second message parameter
	UINT_PTR uIdSubclass,
	[[maybe_unused]] DWORD_PTR dwRefData
)
{
	HTREEITEM		htiItem;
	TV_ITEM			tvi = {};	// 取得用
	WCHAR			cKey;
	SMainMenuWork*	pFuncWk;	// 機能

	switch (uMsg) {
	case WM_GETDLGCODE:
		MSG*	pMsg;
		if (lParam == 0) {
			break;
		}
		pMsg = (MSG*)lParam;
		if (pMsg->wParam == wParam && ( wParam == VK_RETURN|| wParam == VK_ESCAPE || wParam == VK_TAB )) {
			break;
		}
		return DLGC_WANTALLKEYS;
	case WM_KEYDOWN:
		htiItem = TreeView_GetSelection( hwndTree );
		cKey = (WCHAR)MapVirtualKey( wParam, 2 );
		if (cKey > ' ') {
			// アクセスキー設定
			tvi.mask = TVIF_HANDLE | TVIF_PARAM;
			tvi.hItem = htiItem;
			if (!TreeView_GetItem( hwndTree, &tvi )) {
				break;
			}
			pFuncWk = &msMenu[tvi.lParam];
			if (pFuncWk->m_nFunc == F_SEPARATOR) {
				return 0;
			}
			pFuncWk->m_sKey[0] = cKey;
			pFuncWk->m_sKey[1] = L'\0';
			pFuncWk->m_bDupErr = false;
			tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;
			tvi.pszText = const_cast<WCHAR*>( MakeDispLabel( pFuncWk ) );
			TreeView_SetItem( hwndTree , &tvi );		//	キー設定結果を反映
			return 0;
		}

		switch (wParam) {
		case VK_BACK:
		case VK_DELETE:	//	DELキーが押されたらダイアログボックスにメッセージを送信
			::SendMessage( m_hwndDlg, WM_COMMAND, IDC_BUTTON_DELETE, (LPARAM)::GetDlgItem( m_hwndDlg, IDC_BUTTON_DELETE ) );
			return 0;
		case VK_F2:						// F2で編集
			if (htiItem != nullptr) {
				TreeView_EditLabel( hwndTree, htiItem );
			}
			return 0;
		}
		break;
	case WM_CHAR:
		return 0;
	case WM_DESTROY:
		RemoveWindowSubclass(hwndTree, &TreeViewProc, uIdSubclass);
		return 0;
	default:
		break;
	}
	return ::DefSubclassProc(hwndTree, uMsg, wParam, lParam);
}

// TreeViewラベル編集時のメッセージ処理
static LRESULT CALLBACK WindowProcEdit(
	HWND	hwndEdit,	// handle to dialog box
	UINT	uMsg,		// message
	WPARAM	wParam,		// first message parameter
	LPARAM	lParam 		// second message parameter
)
{
	switch (uMsg) {
	case WM_GETDLGCODE:
		return DLGC_WANTALLKEYS;
	}
	return CallWindowProc( m_wpEdit, hwndEdit, uMsg, wParam, lParam );
}

static void SetDlgItemsEnableState(
	HWND	hwndDlg,
	HWND	hwndTreeRes,
	HWND	hwndComboFuncKind,
	HWND	hwndListFunc,
	const CFuncLookup& cLookup
)
{
	HTREEITEM	nIdxMenu = TreeView_GetSelection( hwndTreeRes );
	int			nIdxFIdx = ApiWrap::Combo_GetCurSel( hwndComboFuncKind );
	int			nIdxFunc = ApiWrap::List_GetCurSel( hwndListFunc );
	//i = List_GetCount( hwndTreeRes );
	if (nIdxMenu == nullptr) {
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DELETE ), FALSE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_UP ),     FALSE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DOWN ),   FALSE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_RIGHT ),  FALSE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_LEFT ),   FALSE );
	}
	else{
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DELETE ), TRUE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_UP ),     nullptr != TreeView_GetPrevSibling( hwndTreeRes, nIdxMenu ) );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DOWN ),   nullptr != TreeView_GetNextSibling( hwndTreeRes, nIdxMenu ) );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_RIGHT ),  nullptr != TreeView_GetPrevSibling( hwndTreeRes, nIdxMenu ) );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_LEFT ),   nullptr != TreeView_GetParent( hwndTreeRes, nIdxMenu ) );
	}
	if (LB_ERR == nIdxFunc ||
		( CB_ERR != nIdxFIdx && LB_ERR != nIdxFunc &&
		(cLookup.Pos2FuncCode( nIdxFIdx, nIdxFunc ) == 0 && nIdxFIdx != nSpecialFuncsNum))) {
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_INSERT ), FALSE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_INSERT_A ), FALSE );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_ADD ), FALSE );
	}
	else{
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_INSERT ), nullptr != nIdxMenu );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_INSERT_A ), nullptr != nIdxMenu );
		::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_ADD ), TRUE );
	}
}

/* Menu メッセージ処理 */
INT_PTR CPropMainMenu::DispatchEvent(
	HWND	hwndDlg,	// handle to dialog box
	UINT	uMsg,		// message
	WPARAM	wParam,		// first message parameter
	LPARAM	lParam 		// second message parameter
)
{
	WORD		wNotifyCode;
	WORD		wID;
	HWND		hwndCtl;
	NMHDR*		pNMHDR;
	static HWND	hwndComboFunkKind;
	static HWND	hwndListFunk;
	static HWND	hwndTreeRes;

	int			i;

	int			nIdxFIdx;
	int			nIdxFunc;
	WCHAR		szLabel[256+10];

	EFunctionCode	eFuncCode;
	SMainMenuWork*	pFuncWk;	// 機能
	WCHAR			szKey[2];

	TV_INSERTSTRUCT	tvis;		// 挿入用
	TV_ITEM			tvi;		// 取得用
	HTREEITEM		htiItem;
	HTREEITEM		htiParent;
	HTREEITEM		htiTemp;
	HTREEITEM		htiTemp2;
	TV_DISPINFO*	ptdi;

	CDlgInput1		cDlgInput1;

	static	bool	bInMove;
	bool			bIsNode;

	switch( uMsg ){
	case WM_INITDIALOG:
		/* ダイアログデータの設定 Menu */
		SetData( hwndDlg );
		::SetWindowLongPtr( hwndDlg, DWLP_USER, lParam );

		/* コントロールのハンドルを取得 */
		hwndComboFunkKind = ::GetDlgItem( hwndDlg, IDC_COMBO_FUNCKIND );
		hwndListFunk = ::GetDlgItem( hwndDlg, IDC_LIST_FUNC );
		hwndTreeRes = ::GetDlgItem( hwndDlg, IDC_TREE_RES );

		/* キー選択時の処理 */
		::SendMessage( hwndDlg, WM_COMMAND, MAKELONG( IDC_COMBO_FUNCKIND, CBN_SELCHANGE ), (LPARAM)hwndComboFunkKind );

		// TreeViewのメッセージ処理（アクセスキー入力用）
		m_hwndDlg = hwndDlg;
		::SetWindowSubclass(hwndTreeRes, &TreeViewProc, 0, 0);

		::SetTimer( hwndDlg, 1, 300, nullptr );

		SetDlgItemsEnableState( hwndDlg, hwndTreeRes, hwndComboFunkKind, hwndListFunk, m_cLookup );

		bInMove = false;

		return TRUE;

	case WM_NOTIFY:
		pNMHDR = (NMHDR*)lParam;
		ptdi = (TV_DISPINFO*)lParam;

		switch( pNMHDR->code ){
		case PSN_HELP:
			OnHelp( hwndDlg, IDD_PROP_MAINMENU );
			return TRUE;
		case PSN_KILLACTIVE:
			/* ダイアログデータの取得 Menu */
			GetData( hwndDlg );
			return TRUE;
		case PSN_SETACTIVE:
			m_nPageNum = ID_PROPCOM_PAGENUM_MAINMENU;

			// 表示を更新する（マクロ設定画面でのマクロ名変更を反映）
			nIdxFIdx = ApiWrap::Combo_GetCurSel( hwndComboFunkKind );
			nIdxFunc = ApiWrap::List_GetCurSel( hwndListFunk );
			if( nIdxFIdx != CB_ERR ){
				::SendMessage( hwndDlg, WM_COMMAND, MAKEWPARAM( IDC_COMBO_FUNCKIND, CBN_SELCHANGE ), (LPARAM)hwndComboFunkKind );
				if( nIdxFunc != LB_ERR ){
					ApiWrap::List_SetCurSel( hwndListFunk, nIdxFunc );
				}
			}
			return TRUE;
		case TVN_BEGINLABELEDIT:	//	アイテムの編集開始
			if (pNMHDR->hwndFrom == hwndTreeRes) { 
				HWND hEdit = TreeView_GetEditControl( hwndTreeRes );
				if (msMenu[ptdi->item.lParam].m_bIsNode) {
					// ノードのみ有効
					SetWindowText( hEdit, msMenu[ptdi->item.lParam].m_sName.c_str() ) ;
					ApiWrap::EditCtl_LimitText( hEdit, MAX_MAIN_MENU_NAME_LEN );
					// 編集時のメッセージ処理
					m_wpEdit = (WNDPROC)SetWindowLongPtr( hEdit, GWLP_WNDPROC, (LONG_PTR)WindowProcEdit );
				}
				else {
					// ノード以外編集不可
					SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
				}
			}
			return TRUE;
		case TVN_ENDLABELEDIT:		//	アイテムの編集が終了
 			if (pNMHDR->hwndFrom == hwndTreeRes 
			  && msMenu[ ptdi->item.lParam ].m_bIsNode) {
				// ノード有効
				pFuncWk = &msMenu[ptdi->item.lParam];
				std::wstring strNameOld = pFuncWk->m_sName;
				if (ptdi->item.pszText == nullptr) {
					// Esc
					//	何も設定しない（元のまま）
				}
				else if (wcscmp(ptdi->item.pszText, L"") == 0) {
					// 空
					pFuncWk->m_sName = LS(STR_PROPCOMMAINMENU_EDIT);
				}
				else {
					pFuncWk->m_sName = ptdi->item.pszText;
				}
				if( strNameOld != pFuncWk->m_sName ){
					// ラベルを編集したらリソースからの文字列取得をやめる 2012.10.14 syat 各国語対応
					pFuncWk->m_nFunc = F_NODE;
				}
				ptdi->item.pszText = const_cast<WCHAR*>( MakeDispLabel( pFuncWk ) );
				TreeView_SetItem( hwndTreeRes , &ptdi->item );	//	編集結果を反映

				// 編集時のメッセージ処理を戻す
				SetWindowLongPtr( TreeView_GetEditControl( hwndTreeRes ), GWLP_WNDPROC, (LONG_PTR)m_wpEdit );
				m_wpEdit = nullptr;
			}
			return TRUE;
		case TVN_DELETEITEM:
			if (!bInMove && !msMenu.empty()
			  && pNMHDR->hwndFrom == hwndTreeRes
			  && (htiItem = TreeView_GetSelection( hwndTreeRes )) != nullptr) {
				//付属情報を削除
				tvi.mask = TVIF_HANDLE | TVIF_PARAM;
				tvi.hItem = htiItem;
				if (TreeView_GetItem( hwndTreeRes, &tvi )) {
					msMenu.erase( tvi.lParam );
				}
				return 0;
			}
			break;
		case NM_DBLCLK:
			// ダブルクリック時の処理
			if (pNMHDR->hwndFrom == hwndTreeRes) {
				htiItem = TreeView_GetSelection( hwndTreeRes );
				if (htiItem == nullptr) {
					break;
				}
				tvi.mask = TVIF_HANDLE | TVIF_PARAM;
				tvi.hItem = htiItem;
				if (!TreeView_GetItem( hwndTreeRes, &tvi )) {
					break;
				}
				pFuncWk = &msMenu[tvi.lParam];
				if (pFuncWk->m_nFunc != F_SEPARATOR) {
					auto_sprintf( szKey, L"%ls", pFuncWk->m_sKey);

					if (!cDlgInput1.DoModal(
							G_AppInstance(),
							hwndDlg,
							LS(STR_PROPCOMMAINMENU_ACCKEY1),
							LS(STR_PROPCOMMAINMENU_ACCKEY2),
							1,
							szKey)) {
						return TRUE;
					}
					auto_sprintf( pFuncWk->m_sKey, L"%s", szKey);
					pFuncWk->m_bDupErr = false;

					tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;
					tvi.pszText = const_cast<WCHAR*>( MakeDispLabel( pFuncWk ) );
					TreeView_SetItem( hwndTreeRes, &tvi );
				}
			}
			break;
		}
		break;

	case WM_COMMAND:
		wNotifyCode = HIWORD(wParam);	/* 通知コード */
		wID = LOWORD(wParam);			/* 項目ID､ コントロールID､ またはアクセラレータID */
		hwndCtl = (HWND) lParam;		/* コントロールのハンドル */

		if (hwndComboFunkKind == hwndCtl) {
			switch( wNotifyCode ){
			case CBN_SELCHANGE:
				nIdxFIdx = ApiWrap::Combo_GetCurSel( hwndComboFunkKind );

				::SendMessage( hwndListFunk, WM_SETREDRAW, FALSE, 0 );
				if (nIdxFIdx == nSpecialFuncsNum) {
					// 機能一覧に特殊機能をセット
					ApiWrap::List_ResetContent( hwndListFunk );
					for (i = 0; i < nsFuncCode::nFuncList_Special_Num; i++) {
						ApiWrap::List_AddString( hwndListFunk, LS(nsFuncCode::pnFuncList_Special[i]) );
					}
				}
				else {
					/* 機能一覧に文字列をセット（リストボックス）*/
					m_cLookup.SetListItem( hwndListFunk, nIdxFIdx );
				}
				::SendMessage( hwndListFunk, WM_SETREDRAW, TRUE, 0 );

				return TRUE;
			}
		}
		else{
			switch( wNotifyCode ){
			/* ボタン／チェックボックスがクリックされた */
			case BN_CLICKED:
				switch( wID ){
				case IDC_BUTTON_IMPORT:	/* インポート */
					/* カスタムメニュー設定をインポートする */
					Import( hwndDlg );
					return TRUE;
				case IDC_BUTTON_EXPORT:	/* エクスポート */
					/* カスタムメニュー設定をエクスポートする */
					Export( hwndDlg );
					return TRUE;

				case IDC_BUTTON_CLEAR:
					if (IDCANCEL == ::MYMESSAGEBOX( hwndDlg, MB_OKCANCEL | MB_ICONQUESTION, GSTR_APPNAME,
						LS(STR_PROPCOMMAINMENU_CLEAR)) ) {
						return TRUE;
					}
					// 内部データ初期化
					msMenu.clear();
					nMenuCnt = 0;
					// TreeView初期化
					TreeView_DeleteAllItems( hwndTreeRes );
					return TRUE;

				case IDC_BUTTON_INITIALIZE:
					if (IDCANCEL == ::MYMESSAGEBOX( hwndDlg, MB_OKCANCEL | MB_ICONQUESTION, GSTR_APPNAME,
						LS(STR_PROPCOMMAINMENU_INIT))) {
						return TRUE;
					}
					// 初期状態に戻す
					{
						CDataProfile	cProfile;
						std::vector<std::wstring> data;
						cProfile.SetReadingMode();
						cProfile.ReadProfileRes( MAKEINTRESOURCE(IDR_MENU1), MAKEINTRESOURCE(ID_RC_TYPE_INI), &data );

						CShareData_IO::IO_MainMenu( cProfile, &data, m_Common.m_sMainMenu, false );
						
						SetData( hwndDlg ); 
					}
					return TRUE;

				case IDC_BUTTON_DELETE:
					htiItem = TreeView_GetSelection( hwndTreeRes );
					if (htiItem != nullptr) {
						if (TreeView_GetChild( hwndTreeRes, htiItem ) != nullptr
						  && IDCANCEL == ::MYMESSAGEBOX( hwndDlg, MB_OKCANCEL | MB_ICONQUESTION, GSTR_APPNAME,
							LS(STR_PROPCOMMAINMENU_DEL))) {
							return TRUE;
						}
						htiTemp = TreeView_GetNextSibling( hwndTreeRes, htiItem );
						if (htiTemp == nullptr) {
							// 末尾ならば、前を取る
							htiTemp = TreeView_GetPrevSibling( hwndTreeRes, htiItem );
						}
						TreeView_DeleteItem( hwndTreeRes, htiItem );
						if (htiTemp != nullptr) {
							TreeView_SelectItem( hwndTreeRes, htiTemp );
						}
					}
					break;

				case IDC_BUTTON_INSERT_NODE:			// ノード挿入
				case IDC_BUTTON_INSERTSEPARATOR:		// 区切線挿入
				case IDC_BUTTON_INSERT:					// 挿入(上)
				case IDC_BUTTON_INSERT_A:				// 挿入(下)
				case IDC_BUTTON_ADD:					// 追加
					eFuncCode = F_INVALID;
					bIsNode = false;
					switch (wID) {
					case IDC_BUTTON_INSERT_NODE:		// ノード挿入
						eFuncCode = F_NODE;
						bIsNode = true;
						wcsncpy( szLabel , LS(STR_PROPCOMMAINMENU_EDIT), _countof(szLabel) - 1 );
						szLabel[_countof(szLabel) - 1] = L'\0';
						break;
					case IDC_BUTTON_INSERTSEPARATOR:	// 区切線挿入
						eFuncCode = F_SEPARATOR;
						wcsncpy( szLabel , LS(STR_PROPCOMMAINMENU_SEP), _countof(szLabel) - 1 );
						szLabel[_countof(szLabel) - 1] = L'\0';
						break;
					case IDC_BUTTON_INSERT:				// 挿入
					case IDC_BUTTON_INSERT_A:			// 挿入
					case IDC_BUTTON_ADD:				// 追加
						// Function 取得
						if (CB_ERR == (nIdxFIdx = ApiWrap::Combo_GetCurSel( hwndComboFunkKind ))) {
							return FALSE;
						}
						if (LB_ERR == (nIdxFunc = ApiWrap::List_GetCurSel( hwndListFunk ))) {
							return FALSE;
						}
						if (nIdxFIdx == nSpecialFuncsNum) {
							// 特殊機能
							wcscpy( szLabel, LS(nsFuncCode::pnFuncList_Special[nIdxFunc]) );
							eFuncCode = nsFuncCode::pnFuncList_Special[nIdxFunc];
						}
						else if (m_cLookup.Pos2FuncCode( nIdxFIdx, nIdxFunc ) != 0) {
							ApiWrap::List_GetText( hwndListFunk, nIdxFunc, szLabel );
							eFuncCode = m_cLookup.Pos2FuncCode( nIdxFIdx, nIdxFunc );
						}
						else {
							wcscpy( szLabel, L"?" );
							eFuncCode = F_SEPARATOR;
						}
						break;
					}

					// 挿入位置検索
					htiTemp = TreeView_GetSelection( hwndTreeRes );
					if (htiTemp == nullptr) {
						// 取れなかったらRootの末尾
						htiParent = TVI_ROOT;
						htiTemp = TVI_LAST;
					}
					else {
						if (wID == IDC_BUTTON_ADD) {
							// 追加
							tvi.mask = TVIF_HANDLE | TVIF_PARAM;
							tvi.hItem = htiTemp;
							if (!TreeView_GetItem( hwndTreeRes, &tvi )) {
								// 取れなかったらRootの末尾
								htiParent = TVI_ROOT;
								htiTemp = TVI_LAST;
							}
							else {
								if (msMenu[tvi.lParam].m_bIsNode) {
									// ノード
									htiParent = htiTemp;
									htiTemp = TVI_LAST;
								}
								else {
									// 子を付けられないので親に付ける（選択アイテムの下に付く）
									htiParent = TreeView_GetParent( hwndTreeRes, htiTemp );
									htiTemp = TVI_LAST;
									if (htiParent == nullptr) {
										// 取れなかったらRootの末尾
										htiParent = TVI_ROOT;
									}
								}
							}
						}
						else if (wID == IDC_BUTTON_INSERT_NODE || wID == IDC_BUTTON_INSERT_A) {
							// ノード挿入、挿入(下)
							// 追加先を探る
							htiTemp = TreeView_GetSelection( hwndTreeRes );
							if (htiTemp == nullptr) {
								htiParent = TVI_ROOT;
								htiTemp = TVI_LAST;
							}
							else {
								tvi.mask = TVIF_HANDLE | TVIF_PARAM;
								tvi.hItem = htiTemp;
								if (TreeView_GetItem( hwndTreeRes, &tvi )) {
									if (msMenu[tvi.lParam].m_bIsNode) {
										// ノード
										htiParent = htiTemp;
										htiTemp = TVI_FIRST;
									}
									else {
										// 子を付けられないので親に付ける（選択アイテムの下に付く）
										htiParent = TreeView_GetParent( hwndTreeRes, htiTemp );
										if (htiParent == nullptr) {
											// 取れなかったらRoot
											htiParent = TVI_ROOT;
										}
									}
								}
								else {
									// 取れなかったらRoot
									htiParent = TVI_ROOT;
									htiTemp = TVI_LAST;
								}
							}
						}
						else {
							// 挿入(上)、区切線
							// 挿入先を探る
							htiParent = TreeView_GetParent( hwndTreeRes, htiTemp );
							if (htiParent == nullptr) {
								// 取れなかったらRootのトップ
								htiParent = TVI_ROOT;
								htiTemp = TVI_FIRST;
							}
							else {
								// 一つ手前
								htiTemp = TreeView_GetPrevSibling( hwndTreeRes, htiTemp );
								if (htiTemp == nullptr) {
									// 取れなかったら親の最初
									htiTemp = TVI_FIRST;
								}
							}
						}
					}

					// TreeViewに挿入
					pFuncWk = &msMenu[nMenuCnt];
					pFuncWk->m_nFunc = (EFunctionCode)eFuncCode;
					pFuncWk->m_sName = szLabel;
					pFuncWk->m_bDupErr = false;
					pFuncWk->m_bIsNode = bIsNode;
					pFuncWk->m_sKey[0] = L'\0';
					tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
					tvis.hParent = htiParent;
					tvis.hInsertAfter = htiTemp;
					tvis.item.pszText = const_cast<WCHAR*>(szLabel);
					tvis.item.lParam = nMenuCnt++;
					tvis.item.cChildren = ( wID == IDC_BUTTON_INSERT_NODE );
					htiItem = TreeView_InsertItem( hwndTreeRes, &tvis );
					// 展開
					if (htiParent != TVI_ROOT) {
						TreeView_Expand( hwndTreeRes, htiParent, TVE_EXPAND );
					}
					TreeView_SelectItem( hwndTreeRes, htiItem );

					// リストを1つ進める
					switch (wID) {
					case IDC_BUTTON_INSERT:				// 挿入
					case IDC_BUTTON_INSERT_A:			// 挿入
					case IDC_BUTTON_ADD:				// 追加
						ApiWrap::List_SetCurSel( hwndListFunk, nIdxFunc+1 );
						break;
					}
					break;

				case IDC_BUTTON_UP:
					htiItem = TreeView_GetSelection( hwndTreeRes );
					if (htiItem == nullptr) {
						break;
					}
					htiTemp = TreeView_GetPrevSibling( hwndTreeRes, htiItem );
					if (htiTemp == nullptr) {
						// そのエリアで最初
						break;
					}

					// コピー
					bInMove = true;
					TreeCopy(hwndTreeRes, htiItem, htiTemp, false, true);

					// 削除
					TreeView_DeleteItem( hwndTreeRes, htiTemp );
					bInMove = false;
					break;

				case IDC_BUTTON_DOWN:
					htiItem = TreeView_GetSelection( hwndTreeRes );
					if (htiItem == nullptr) {
						break;
					}
					htiTemp = TreeView_GetNextSibling( hwndTreeRes, htiItem );
					if (htiTemp == nullptr) {
						// そのエリアで最後
						break;
					}

					// コピー
					bInMove = true;
					TreeCopy(hwndTreeRes, htiTemp, htiItem, false, true);

					// 削除
					TreeView_DeleteItem( hwndTreeRes, htiItem );
					bInMove = false;

					// 選択
					htiItem = TreeView_GetNextSibling( hwndTreeRes, htiTemp );
					if (htiItem != nullptr) {
						TreeView_SelectItem( hwndTreeRes, htiItem );
					}
					break;

				case IDC_BUTTON_RIGHT:
					htiItem = TreeView_GetSelection( hwndTreeRes );
					if (htiItem == nullptr) {
						break;
					}
					htiTemp = TreeView_GetPrevSibling( hwndTreeRes, htiItem );
					if (htiTemp == nullptr) {
						// そのエリアで最初
						break;
					}
					// ノード確認
					tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_CHILDREN;
					tvi.hItem = htiTemp;
					i = TreeView_GetItem( hwndTreeRes, &tvi );
					if (!TreeView_GetItem( hwndTreeRes, &tvi )) {
						// エラー
						break;
					}
					if (tvi.cChildren) {
						// 直前がノード
						HTREEITEM		htiTemp2;
						// コピー
						bInMove = true;
						htiTemp2 = TreeCopy(hwndTreeRes, htiTemp, htiItem, true, true);

						// 削除
						TreeView_DeleteItem( hwndTreeRes, htiItem );
						bInMove = false;

						// 選択
						TreeView_SelectItem( hwndTreeRes, htiTemp2 );
					}
					else {
						// ノードが無い
						break;
					}
					break;

				case IDC_BUTTON_LEFT:
					htiItem = TreeView_GetSelection( hwndTreeRes );
					if (htiItem == nullptr) {
						break;
					}
					htiParent = TreeView_GetParent( hwndTreeRes, htiItem );
					if (htiParent == nullptr) {
						// Root
						break;
					}
					// コピー
					bInMove = true;
					htiTemp2 = TreeCopy(hwndTreeRes, htiParent, htiItem, false, true);

					// 削除
					TreeView_DeleteItem( hwndTreeRes, htiItem );
					bInMove = false;

					// 選択
					TreeView_SelectItem( hwndTreeRes, htiTemp2 );
					break;

				case IDC_BUTTON_CHECK:		// メニューの検査
					{
						std::wstring sErrMsg;
						if (Check_MainMenu( hwndTreeRes, sErrMsg )) {
							InfoMessage( hwndDlg, LS(STR_PROPCOMMAINMENU_OK));
						}
						else {
							WarningMessage( hwndDlg, sErrMsg.c_str() );
						}
					}
					break;

				case IDC_BUTTON_EXPAND:		// ツリー全開
					ApiWrap::TreeView_ExpandAll( hwndTreeRes, true );
					break;

				case IDC_BUTTON_COLLAPSE:	// ツリー全閉
					ApiWrap::TreeView_ExpandAll( hwndTreeRes, false );
					break;
				}

				break;
			}
		}
		break;

	case WM_TIMER:
		SetDlgItemsEnableState( hwndDlg, hwndTreeRes, hwndComboFunkKind, hwndListFunk, m_cLookup );
		break;
	case WM_DESTROY:
		::KillTimer( hwndDlg, 1 );

		// ワークのクリア
		msMenu.clear();
		nMenuCnt = 0;
		break;

	case WM_HELP:
		{
			HELPINFO *p = (HELPINFO *)lParam;
			MyWinHelp( (HWND)p->hItemHandle, HELP_WM_HELP, (ULONG_PTR)(LPVOID)p_helpids );
		}
		return TRUE;

	//Context Menu
	case WM_CONTEXTMENU:
		MyWinHelp( hwndDlg, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)p_helpids );

		return TRUE;
	}
	return FALSE;
}

// & の補完
static std::wstring	SupplementAmpersand( std::wstring sLavel)
{
	size_t	nPos =0;
	while ((nPos = sLavel.find( L'&', nPos)) != std::wstring::npos) {
		if (sLavel[nPos+1] != L'&') {
			// &&でない
			sLavel.replace( nPos, 1, L"&&");
		}
		nPos +=2;
	}
	return sLavel;
}

// & の削除
static std::wstring	RemoveAmpersand( std::wstring sLavel)
{
	size_t	nPos =0;
	while ((nPos = sLavel.find( L'&', nPos)) != std::wstring::npos) {
		if (sLavel[nPos+1] == L'&') {
			// &&
			sLavel.replace( nPos, 1, L"");
		}
		nPos ++;
	}
	return sLavel;
}

/* ダイアログデータの設定 MainMenu */
void CPropMainMenu::SetData( HWND hwndDlg )
{
	CMainMenu*		pcMenuTBL = m_Common.m_sMainMenu.m_cMainMenuTbl;
	CMainMenu*		pcFunc;
	HWND			hwndCombo;
	HWND			hwndCheck;
	HWND			hwndTreeRes;
	const int		MAX_LABEL_CCH = 256+10;
	WCHAR			szLabel[MAX_LABEL_CCH];
	int				nCurLevel;
	HTREEITEM		htiItem;
	HTREEITEM		htiParent;
	TV_INSERTSTRUCT	tvis;			// 挿入用
	SMainMenuWork*	pFuncWk;		// 機能(work)
	int 			i;

	/* 機能種別一覧に文字列をセット（コンボボックス） */
	hwndCombo = ::GetDlgItem( hwndDlg, IDC_COMBO_FUNCKIND );
	m_cLookup.SetCategory2Combo( hwndCombo );

	// 特別機能追加
	nSpecialFuncsNum = ApiWrap::Combo_AddString( hwndCombo, LS( STR_SPECIAL_FUNC ) );

	/* 種別の先頭の項目を選択（コンボボックス）*/
	ApiWrap::Combo_SetCurSel( hwndCombo, 0 );

	// ワーク、TreeViewの初期化
	msMenu.clear();
	nMenuCnt = 0;

	hwndTreeRes = ::GetDlgItem( hwndDlg, IDC_TREE_RES );
	TreeView_DeleteAllItems( hwndTreeRes );

	// アクセスキーを( )付で表示
	hwndCheck = ::GetDlgItem( hwndDlg, IDC_CHECK_KEY_PARENTHESES );
	ApiWrap::BtnCtl_SetCheck( hwndCheck, m_Common.m_sMainMenu.m_bMainMenuKeyParentheses );

	/* メニュー項目一覧と内部データをセット（TreeView）*/
	nCurLevel = 0;
	htiParent = TVI_ROOT;
	htiItem = TreeView_GetRoot( hwndTreeRes );
	for (i = 0; i < m_Common.m_sMainMenu.m_nMainMenuNum; i++) {
		pcFunc = &pcMenuTBL[i];
		if (pcFunc->m_nLevel < nCurLevel) {
			// Level Up
			for (; pcFunc->m_nLevel < nCurLevel; nCurLevel--) {
				htiParent = (htiParent == TVI_ROOT) ? TVI_ROOT : TreeView_GetParent( hwndTreeRes, htiParent );
				if (htiParent == nullptr)		htiParent = TVI_ROOT;
			}
		}
		else if (pcFunc->m_nLevel > nCurLevel) {
			// Level Down
			for ( htiParent = htiItem, nCurLevel++; pcFunc->m_nLevel < nCurLevel; nCurLevel++) {
				// 実行されることは無いはず（データが正常ならば）
				htiParent = TreeView_GetChild( hwndTreeRes, htiItem );
				if (htiParent == nullptr)		htiParent = htiItem;
			}
		}

		// 内部データを作成
		pFuncWk = &msMenu[nMenuCnt];
		pFuncWk->m_nFunc = pcFunc->m_nFunc;
		pFuncWk->m_bIsNode = false;
		switch (pcFunc->m_nType) {
			case T_LEAF:
				m_cLookup.Funccode2Name( pcFunc->m_nFunc, szLabel, MAX_LABEL_CCH );
				pFuncWk->m_sName = szLabel;
				break;
			case T_SEPARATOR:
				pFuncWk->m_sName = LS(STR_PROPCOMMAINMENU_SEP);
				break;
			case T_SPECIAL:
				// 2014.05.04 各国語対応
				pFuncWk->m_sName = LS(pcFunc->m_nFunc);
				break;
			case T_NODE:
				pFuncWk->m_bIsNode = true;
				// ラベル編集後のノードはiniから、それ以外はリソースからラベルを取得 2012.10.14 syat 各国語対応
				if (pFuncWk->m_nFunc == F_NODE) {
					pFuncWk->m_sName = RemoveAmpersand( pcFunc->m_sName );
				} else {
					pFuncWk->m_sName = LS( pFuncWk->m_nFunc );
				}
				break;
		}
		wcscpy(pFuncWk->m_sKey, pcFunc->m_sKey);
		pFuncWk->m_bDupErr = false;
		// TreeViewに挿入
		tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
		tvis.hParent = htiParent;
		tvis.hInsertAfter = TVI_LAST;
		tvis.item.pszText = const_cast<WCHAR*>( MakeDispLabel( pFuncWk ) );
		tvis.item.lParam = nMenuCnt++;								// 内部データインデックスのインクリメント
		tvis.item.cChildren = ( pcFunc->m_nType == T_NODE );
		htiItem = TreeView_InsertItem( hwndTreeRes, &tvis );
	}
}

/* ダイアログデータの取得 MainMenu */
int CPropMainMenu::GetData( HWND hwndDlg )
{
	HWND			hwndTreeRes;
	HWND			hwndCheck;
	HTREEITEM		htiItem;

	// アクセスキーを( )付で表示
	hwndCheck = ::GetDlgItem( hwndDlg, IDC_CHECK_KEY_PARENTHESES );
	m_Common.m_sMainMenu.m_bMainMenuKeyParentheses = (ApiWrap::BtnCtl_GetCheck( hwndCheck ) != 0);

	// メニュートップ項目をセット
	m_Common.m_sMainMenu.m_nMainMenuNum = 0;
	memset( m_Common.m_sMainMenu.m_nMenuTopIdx, -1, sizeof(m_Common.m_sMainMenu.m_nMenuTopIdx) );

	hwndTreeRes = ::GetDlgItem( hwndDlg, IDC_TREE_RES );

	htiItem = TreeView_GetRoot( hwndTreeRes );
	GetDataTree( hwndTreeRes, htiItem, 0);

	return TRUE;
}

/* ダイアログデータの取得 TreeViewの 1 level */
bool CPropMainMenu::GetDataTree( HWND hwndTree, HTREEITEM htiTrg, int nLevel )
{
	static	bool	bOptionOk;
	CMainMenu*		pcMenuTBL = m_Common.m_sMainMenu.m_cMainMenuTbl;
	CMainMenu*		pcFunc;
	HTREEITEM		s;
	HTREEITEM		ts;
	TV_ITEM			tvi;			// 取得用
	SMainMenuWork*	pFuncWk;		// 機能(work)
	int 			nTopCount = 0;

	if (nLevel == 0) {
		// 共通設定フラグ
		bOptionOk = false;
	}

	for (s = htiTrg; s != nullptr; s = TreeView_GetNextSibling( hwndTree, s )) {
		if (m_Common.m_sMainMenu.m_nMainMenuNum >= MAX_MAINMENU) {
			// 登録数 over
			return false;
		}
		tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_CHILDREN;
		tvi.hItem = s;
		if (!TreeView_GetItem( hwndTree, &tvi )) {
			// Error
			return false;
		}
		pFuncWk = &msMenu[tvi.lParam];

		if (nLevel == 0) {
			if (nTopCount >= MAX_MAINMENU_TOP) {
				continue;
			}
			// Top Levelの記録
			m_Common.m_sMainMenu.m_nMenuTopIdx[nTopCount++] = m_Common.m_sMainMenu.m_nMainMenuNum;
		}
		pcFunc = &pcMenuTBL[m_Common.m_sMainMenu.m_nMainMenuNum++];

		switch(pFuncWk->m_nFunc) {
		case F_NODE:
			pcFunc->m_nType = T_NODE;
			wcscpy_s( pcFunc->m_sName, MAX_MAIN_MENU_NAME_LEN+1, SupplementAmpersand( pFuncWk->m_sName ).c_str() );
			break;
		case F_SEPARATOR:
			pcFunc->m_nType = T_SEPARATOR;
			pcFunc->m_sName[0] = L'\0';
			break;
		default:
			if ( pFuncWk->m_bIsNode ) {
				// コマンド定義外のIDの場合、ノードとして扱う 2012.10.14 syat 各国語対応
				pcFunc->m_nType = T_NODE;
				pcFunc->m_sName[0] = L'\0';	// 名前は、リソースから取得するため空白に設定
				break;
			}
			if (pFuncWk->m_nFunc >= F_SPECIAL_FIRST && pFuncWk->m_nFunc <= F_SPECIAL_LAST) {
				pcFunc->m_nType = T_SPECIAL;
				// 2014.05.04 nLevel == 0 のときも"名前なし"にする
				pcFunc->m_sName[0] = L'\0';
			}
			else {
				if (pFuncWk->m_nFunc == F_OPTION) {
					bOptionOk = true;
				}
				pcFunc->m_nType = T_LEAF;
				pcFunc->m_sName[0] = L'\0';
			}
			break;
		}
		pcFunc->m_nFunc = pFuncWk->m_nFunc;
		wcscpy( pcFunc->m_sKey, pFuncWk->m_sKey );
		pcFunc->m_nLevel = nLevel;

		if (tvi.cChildren) {
			ts = TreeView_GetChild( hwndTree, s );	//	子の取得
			if (ts != nullptr) {
				if (!GetDataTree( hwndTree, ts, nLevel+1 )) {
					return false;
				}
			}
		}
	}

	if (nLevel == 0 && !bOptionOk) {
		// 共通設定が無い
		if (nTopCount < MAX_MAINMENU_TOP && m_Common.m_sMainMenu.m_nMainMenuNum+1 < MAX_MAINMENU) {
			// Top Levelの記録
			m_Common.m_sMainMenu.m_nMenuTopIdx[nTopCount++] = m_Common.m_sMainMenu.m_nMainMenuNum;
			// Top Levelの追加（ダミー）
			pcFunc = &pcMenuTBL[m_Common.m_sMainMenu.m_nMainMenuNum++];
			pcFunc->m_nType = T_NODE;
			pcFunc->m_nFunc = F_NODE;
			wcscpy( pcFunc->m_sName, L"auto_add" );
			pcFunc->m_sKey[0] = L'\0';
			pcFunc->m_nLevel = nLevel++;
		}
		else {
			// 末尾に追加を指定
			nLevel = 1;
		}
		if (m_Common.m_sMainMenu.m_nMainMenuNum < MAX_MAINMENU) {
			// 共通設定
			pcFunc = &pcMenuTBL[m_Common.m_sMainMenu.m_nMainMenuNum++];
			pcFunc->m_nType = T_LEAF;
			pcFunc->m_nFunc = F_OPTION;
			pcFunc->m_sName[0] = L'\0';
			pcFunc->m_sKey[0] = L'\0';
			pcFunc->m_nLevel = nLevel;
		}
		else {
			// 登録数 over
			return false;
		}
	}

	return true;
}

/* メインメニュー設定をインポートする */
void CPropMainMenu::Import( HWND hwndDlg )
{
	CImpExpMainMenu	cImpExp( m_Common );

	// インポート
	if (!cImpExp.ImportUI( G_AppInstance(), hwndDlg )) {
		// インポートをしていない
		return;
	}
	SetData( hwndDlg );
}

/* メインメニュー設定をエクスポートする */
void CPropMainMenu::Export( HWND hwndDlg )
{
	CImpExpMainMenu	cImpExp( m_Common );

	GetData( hwndDlg );

	// エクスポート
	if (!cImpExp.ExportUI( G_AppInstance(), hwndDlg )) {
		// エクスポートをしていない
		return;
	}
}

// ツリーのコピー
//		fChildがtrueの時はdstの子としてコピー, そうでなければdstの兄弟としてdstの後ろにコピー
//		fOnryOneがtrueの時は1つだけコピー（子があったらコピー）
static HTREEITEM TreeCopy( HWND hwndTree, HTREEITEM dst, HTREEITEM src, bool fChild, bool fOnryOne )
{
	HTREEITEM		s;
	HTREEITEM		ts;
	HTREEITEM		td = nullptr;
	TV_INSERTSTRUCT	tvis;		// 挿入用
	TV_ITEM			tvi;		// 取得用
	int				n = 0;
	const int		MAX_LABEL_CCH = 256+10;
	WCHAR			szLabel[MAX_LABEL_CCH];

	for (s = src; s != nullptr; s = fOnryOne ? nullptr:TreeView_GetNextSibling( hwndTree, s )) {
		tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
		tvi.hItem = s;
		tvi.pszText = szLabel;
		tvi.cchTextMax = MAX_LABEL_CCH;
		if (!TreeView_GetItem( hwndTree, &tvi )) {
			// Error
			break;
		}
		tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_CHILDREN;
		if (fChild || n != 0) {
			// dstの子供として作成
			tvis.hParent = dst;
			tvis.hInsertAfter = TVI_LAST;
		}
		else {
			//	dstの兄弟として作成
			tvis.hParent = TreeView_GetParent( hwndTree, dst );
			tvis.hInsertAfter = dst;
		}
		tvis.item.pszText = szLabel;
		tvis.item.lParam = tvi.lParam;
		tvis.item.cChildren = tvi.cChildren;
		td = TreeView_InsertItem( hwndTree, &tvis );	//	Itemの作成

		if (tvi.cChildren) {
			ts = TreeView_GetChild( hwndTree, s );	//	子の取得
			if (ts != nullptr) {
				TreeCopy( hwndTree, td, ts, true, false );
			}
			// 展開
			if (tvi.state & TVIS_EXPANDEDONCE) {
				TreeView_Expand( hwndTree, td, TVE_EXPAND );
			}
		}
		n++;
	}

	return td;
}

// 表示用データの作成（アクセスキー付加）
static const WCHAR* MakeDispLabel( SMainMenuWork* pFunc )
{
	static	WCHAR	szLabel[MAX_MAIN_MENU_NAME_LEN + 10];

	if (pFunc->m_sKey[0]) {
		auto_snprintf_s( szLabel, MAX_MAIN_MENU_NAME_LEN + 10, L"%ls%ls(%ls)",
			pFunc->m_bDupErr ? L">" : L"",
			pFunc->m_sName.substr(0, MAX_MAIN_MENU_NAME_LEN).c_str(), pFunc->m_sKey);
	}
	else {
		auto_snprintf_s( szLabel, MAX_MAIN_MENU_NAME_LEN + 10, L"%ls%ls",
			pFunc->m_bDupErr ? L">" : L"",
			pFunc->m_sName.substr(0, MAX_MAIN_MENU_NAME_LEN).c_str() );
	}

	return szLabel;
}

// メニューの検査
bool CPropMainMenu::Check_MainMenu( 
	HWND	hwndTree,		// handle to TreeView
	std::wstring&	sErrMsg			// エラーメッセージ
)
{
	HTREEITEM		htiItem;
	
	sErrMsg.clear();
	
	htiItem = TreeView_GetRoot( hwndTree );

	bool bRet = Check_MainMenu_Sub( hwndTree, htiItem, 0, sErrMsg );
	return bRet;
}

// メニューの検査 TreeViewの 1 level
bool CPropMainMenu::Check_MainMenu_Sub(
	HWND		hwndTree,		// handle to dialog box
	HTREEITEM 	htiTrg,			// ターゲット
	int 		nLevel,
	std::wstring&	sErrMsg )
{
	// 検査用
	static	bool		bOptionOk;		// 「共通設定」
	static	int 		nMenuNum;		// メニュー項目数		最大 MAX_MAINMENU
	static	int 		nTopNum;		// トップレベル項目数	最大 MAX_MAINMENU_TOP
	static	int 		nDupErrNum;		// 重複エラー個数
	static	int 		nNoSetErrNum;	// 未設定エラー個数
	static	HTREEITEM	htiErr;
	//
	bool			bRet = true;
	EMainMenuType	nType;
	HTREEITEM		s;
	HTREEITEM		ts;
	TV_ITEM			tvi;							// 取得用
	SMainMenuWork*	pFuncWk;						// 機能(work)
	std::map< WCHAR, HTREEITEM >	mKey;			// 重複エラー検出用

	if (nLevel == 0) {
		bOptionOk = false;
		nMenuNum = nTopNum = nDupErrNum = nNoSetErrNum = 0;
		htiErr = nullptr;
	}
	mKey.clear();

	for (s = htiTrg; s != nullptr; s = TreeView_GetNextSibling( hwndTree, s )) {
		// メニュー数のカウント
		nMenuNum++;
		if (nLevel == 0) {
			nTopNum++;
		}
		tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_CHILDREN;
		tvi.hItem = s;
		if (!TreeView_GetItem( hwndTree, &tvi )) {
			// Error
			sErrMsg = LS(STR_PROPCOMMAINMENU_ERR1);
			return false;
		}
		pFuncWk = &msMenu[tvi.lParam];
		switch (pFuncWk->m_nFunc) {
		case F_NODE:
			nType = T_NODE;
			break;
		case F_SEPARATOR:
			nType = T_SEPARATOR;
			break;
		default:
			if (pFuncWk->m_nFunc >= F_SPECIAL_FIRST && pFuncWk->m_nFunc <= F_SPECIAL_LAST) {
				nType = T_SPECIAL;
			}
			else if (pFuncWk->m_bIsNode) {
				nType = T_NODE;
			}
			else {
				if (pFuncWk->m_nFunc == F_OPTION) {
					bOptionOk = true;
				}
				nType = T_LEAF;
			}
			break;
		}
		if (pFuncWk->m_sKey[0] == '\0') {
			if (nType == T_NODE || nType == T_LEAF) {
				// 未設定
				if (nNoSetErrNum == 0) {
					if (htiErr == nullptr) {
						htiErr = s;
					}
				}
				TreeView_SelectItem( hwndTree, s );
				nNoSetErrNum++;
			}
		}
		else {
			auto itKey = mKey.find( pFuncWk->m_sKey[0] );
			if (itKey == mKey.end()) {
				mKey[pFuncWk->m_sKey[0]] = s;

				if (pFuncWk->m_bDupErr) {
					// 目印クリア
					pFuncWk->m_bDupErr = false;
					tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;
					tvi.pszText =  const_cast<WCHAR*>( MakeDispLabel( pFuncWk ) );
					TreeView_SetItem( hwndTree , &tvi );		//	キー設定結果を反映
				}
			}
			else {
				// 重複エラー
				if (nDupErrNum == 0) {
					if (htiErr == nullptr) {
						htiErr = mKey[pFuncWk->m_sKey[0]];
					}
				}
				TreeView_SelectItem( hwndTree, mKey[pFuncWk->m_sKey[0]] );

				nDupErrNum++;

				// 目印設定
				pFuncWk->m_bDupErr = true;
				tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;
				tvi.pszText = const_cast<WCHAR*>( MakeDispLabel( pFuncWk ) );
				TreeView_SetItem( hwndTree , &tvi );		//	キー設定結果を反映

				// 目印設定（元分）
				tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_CHILDREN;
				tvi.hItem = mKey[pFuncWk->m_sKey[0]];
				if (!TreeView_GetItem( hwndTree, &tvi )) {
					// Error
					sErrMsg = LS(STR_PROPCOMMAINMENU_ERR1);
					return false;
				}
				if (!msMenu[tvi.lParam].m_bDupErr) {
					msMenu[tvi.lParam].m_bDupErr = true;
					tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_PARAM;
					tvi.pszText = const_cast<WCHAR*>( MakeDispLabel( &msMenu[tvi.lParam] ) );
					TreeView_SetItem( hwndTree , &tvi );		//	キー設定結果を反映
				}
			}
		}
		if (tvi.cChildren) {
			ts = TreeView_GetChild( hwndTree, s );	//	子の取得
			if (ts != nullptr) {
				if (!Check_MainMenu_Sub( hwndTree, ts, nLevel+1, sErrMsg )) {
					// 内部エラー
					return false;
				}
			}
		}
	}

	if (nLevel == 0) {
		sErrMsg.clear();
		if (!bOptionOk) {
			sErrMsg += LS(STR_PROPCOMMAINMENU_ERR2);
			bRet = false;
		}
		if (nTopNum > MAX_MAINMENU_TOP) {
			sErrMsg += LS(STR_PROPCOMMAINMENU_ERR3);
			bRet = false;
		}
		if (nMenuNum > MAX_MAINMENU) {
			sErrMsg += LS(STR_PROPCOMMAINMENU_ERR4);
			bRet = false;
		}
		if (nDupErrNum > 0) {
			sErrMsg += LS(STR_PROPCOMMAINMENU_ERR5);
			bRet = false;
		}
		if (nNoSetErrNum > 0) {
			sErrMsg += LS(STR_PROPCOMMAINMENU_ERR6);
			bRet = false;
		}
		if (htiErr != nullptr) {
			TreeView_SelectItem( hwndTree, htiErr );
			TreeView_SelectSetFirstVisible( hwndTree, htiErr );
		}
	}
	return bRet;
}
